home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1995 #5 & #6
/
Amiga Plus CD - 1995 - No. 5 and 6.iso
/
pd
/
netz
/
magplip
/
source
/
server.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-20
|
28KB
|
944 lines
/*
** $VER: server.c 1.9 (20 Aug 1995)
**
** magplip.device - Parallel Line Internet Protocol
**
** Original code written by Oliver Wagner and Michael Balzer.
**
** This version has been completely reworked by Marius Gröger, introducing
** slight protocol changes. The new source is a lot better organized and
** maintainable.
**
** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
** The new source is significantly faster and yet better maintainable.
**
** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
** (C) Copyright 1995 Marius Gröger
** (C) Copyright 1995 Jan Kratochvil & Martin Mares
** All Rights Reserved
**
** $HISTORY:
**
** 20 Aug 1995 : 001.009 : support for ASM xfer routines
** removed obsolete CIA macros (mag/jk/mm)
** 29 Jul 1995 : 001.008 : support for arbitration delay
** symmetrical handling
** 26 Apr 1995 : 001.007 : _very_ nasty bug would miss packets and get
** the driver totally irritated
** 25 Apr 1995 : 001.006 : now compiles with ANSI and STRICT
** fixed bug with resource allocation
** 08 Mar 1995 : 001.005 : write req. are now handled by device.c
** 06 Mar 1995 : 001.004 : collision delay added
** 06 Mar 1995 : 001.003 : hardware transmission errors are no longer retried
** because this is any upper layers job
** 04 Mar 1995 : 001.002 : event tracking *much* more conform to SANA-2
** 18 Feb 1995 : 001.001 : startup now a bit nicer
** using BASEPTR
** 12 Feb 1995 : 001.000 : reworked original
*/
#define DEBUG 0
/*F*/ /* includes */
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#endif
#ifndef CLIB_DOS_PROTOS_H
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#endif
#ifndef CLIB_CIA_PROTOS_H
#include <clib/cia_protos.h>
#include <pragmas/cia_pragmas.h>
#endif
#ifndef CLIB_MISC_PROTOS_H
#include <clib/misc_protos.h>
#include <pragmas/misc_pragmas.h>
#endif
#ifndef CLIB_TIME_PROTOS_H
#include <clib/timer_protos.h>
#include <pragmas/timer_pragmas.h>
#endif
#ifndef CLIB_UTILITY_PROTOS_H
#include <clib/utility_protos.h>
#include <pragmas/utility_pragmas.h>
#endif
#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef EXEC_INTERRUPTS_H
#include <exec/interrupts.h>
#endif
#ifndef EXEC_DEVICES_H
#include <exec/devices.h>
#endif
#ifndef EXEC_IO_H
#include <exec/io.h>
#endif
#ifndef DEVICES_SANA2_H
#include <devices/sana2.h>
#endif
#ifndef HARDWARE_CIA_H
#include <hardware/cia.h>
#endif
#ifndef RESOURCES_MISC_H
#include <resources/misc.h>
#endif
#ifndef _STRING_H
#include <string.h>
#endif
#ifndef __MAGPLIP_H
#include "magplip.h"
#endif
#ifndef __DEBUG_H
#include "debug.h"
#endif
/*E*/
/*F*/ /* defines, types and enums */
/*
** return codes for arbitratedwrite()
*/
typedef enum { AW_OK, AW_ABORTED, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT;
/*E*/
/*F*/ /* imports */
extern VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
extern VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
extern USHORT ASM CRC16(REG(a0) UBYTE *, REG(d0) SHORT);
extern BOOL ASM hwsend(REG(a0) BASEPTR);
extern BOOL ASM hwrecv(REG(a0) BASEPTR);
extern VOID ASM interrupt(REG(a1) BASEPTR);
extern FAR volatile struct CIA ciaa,ciab;
/*E*/
/*F*/ /* exports */
extern VOID __saveds ServerTask(VOID);
/*E*/
/*F*/ /* statics */
static struct PLIPBase *startup(void);
static REGARGS VOID DoEvent(BASEPTR, long event);
static VOID readargs(BASEPTR);
static BOOL init(BASEPTR);
static BOOL hwattach(BASEPTR);
static VOID hwdetach(BASEPTR);
static REGARGS BOOL goonline(BASEPTR);
static REGARGS VOID gooffline(BASEPTR);
static REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2);
static REGARGS VOID dowritereqs(BASEPTR);
static REGARGS VOID doreadreqs(BASEPTR);
static REGARGS VOID dos2reqs(BASEPTR);
/*E*/
/*F*/ /* CIA access macros & functions */
#define CLEARINT SetICR(CIAABase, CIAICRF_FLG)
#define DISABLEINT AbleICR(CIAABase, CIAICRF_FLG)
#define ENABLEINT AbleICR(CIAABase, CIAICRF_FLG | CIAICRF_SETCLR)
#define SETCIAOUTPUT ciaa.ciaddrb = 0xFF
#define SETCIAINPUT ciaa.ciaddrb = 0x00
#define PARINIT(b) SETCIAINPUT; \
ciab.ciaddra &= ~((b)->pb_HandshakeMask[HS_LINE]); \
ciab.ciaddra |= (b)->pb_HandshakeMask[HS_REQUEST]
#define TESTLINE(b) (ciab.ciapra & (b)->pb_HandshakeMask[HS_LINE])
#define SETREQUEST(b) ciab.ciapra |= (b)->pb_HandshakeMask[HS_REQUEST]
#define CLEARREQUEST(b) ciab.ciapra &= ~((b)->pb_HandshakeMask[HS_REQUEST])
/*E*/
/*
** functions to gain hardware, initialise communication
** and to release hardware
*/
/*F*/ static BOOL hwattach(BASEPTR)
{
BOOL rc = FALSE;
d(("entered\n"));
if (MiscBase = OpenResource("misc.resource"))
{
if (CIAABase = OpenResource("ciaa.resource"))
{
CiaBase = CIAABase;
d(("ciabase is %lx\n",CiaBase));
/* obtain exclusive access to the parallel hardware */
if (!AllocMiscResource(MR_PARALLELPORT, pb->pb_DevNode.lib_Node.ln_Name))
{
pb->pb_AllocFlags |= 1;
if (!AllocMiscResource(MR_PARALLELBITS, pb->pb_DevNode.lib_Node.ln_Name))
{
pb->pb_AllocFlags |= 2;
/* Add our interrupt to handle CIAICRB_FLG.
** This is also cia.resource means of granting exclusive
** access to the related registers in the CIAs.
*/
pb->pb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
pb->pb_Interrupt.is_Node.ln_Pri = 127;
pb->pb_Interrupt.is_Node.ln_Name = SERVERTASKNAME;
pb->pb_Interrupt.is_Data = (APTR)pb;
pb->pb_Interrupt.is_Code = (VOID (*)())&interrupt;
/* We must Disable() bcos there could be an interrupt already
** waiting for us. We may, however, not Able/SetICR() before
** we have access!
*/
Disable();
if (!AddICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt))
{
DISABLEINT; /* this is what I meant */
rc = TRUE;
}
Enable();
if (rc)
{
pb->pb_AllocFlags |= 4;
PARINIT(pb); /* cia to input, handshake in/out setting */
CLEARREQUEST(pb); /* setup handshake lines */
CLEARINT; /* clear this interrupt */
ENABLEINT; /* allow interrupts */
}
}
else
d(("no parallelbits\n"));
}
else
d(("no parallelport\n"));
}
else
d(("no misc resource\n"));
}
else
d(("no misc resource\n"));
return rc;
}
/*E*/
/*F*/ static VOID hwdetach(BASEPTR)
{
if (pb->pb_AllocFlags & 4)
{
DISABLEINT;
CLEARINT;
RemICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt);
}
if (pb->pb_AllocFlags & 2) FreeMiscResource(MR_PARALLELBITS);
if (pb->pb_AllocFlags & 1) FreeMiscResource(MR_PARALLELPORT);
pb->pb_AllocFlags = 0;
}
/*E*/
/*
** functions to go online/offline
*/
/*F*/ static REGARGS VOID rejectpackets(BASEPTR)
{
struct IOSana2Req *ios2;
ObtainSemaphore(&pb->pb_WriteListSem);
while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList))
{
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
DevTermIO(pb,ios2);
}
ReleaseSemaphore(&pb->pb_WriteListSem);
ObtainSemaphore(&pb->pb_ReadListSem);
while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList))
{
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
DevTermIO(pb,ios2);
}
ReleaseSemaphore(&pb->pb_ReadListSem);
ObtainSemaphore(&pb->pb_ReadOrphanListSem);
while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList))
{
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
DevTermIO(pb,ios2);
}
ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
}
/*E*/
/*F*/ static REGARGS BOOL goonline(BASEPTR)
{
BOOL rc = FALSE;
d(("trying to go online\n"));
if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
{
if (!hwattach(pb))
{
d(("error going online\n"));
}
else
{
GetSysTime(&pb->pb_DevStats.LastStart);
pb->pb_Flags &= ~(PLIPF_OFFLINE | PLIPF_NOTCONFIGURED);
DoEvent(pb, S2EVENT_ONLINE);
rc = TRUE;
d(("i'm now online!\n"));
}
}
return rc;
}
/*E*/
/*F*/ static REGARGS VOID gooffline(BASEPTR)
{
if (!(pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED)))
{
hwdetach(pb);
pb->pb_Flags |= PLIPF_OFFLINE;
DoEvent(pb, S2EVENT_OFFLINE);
}
d(("ok!\n"));
}
/*E*/
/*
** SANA-2 Event management
*/
/*F*/ static REGARGS VOID DoEvent(BASEPTR, long event)
{
struct IOSana2Req *ior, *ior2;
d(("event is %lx\n",event));
ObtainSemaphore(&pb->pb_EventListSem );
for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head;
ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
ior = ior2 )
{
if (ior->ios2_WireError & event)
{
Remove((struct Node*)ior);
DevTermIO(pb, ior);
}
}
ReleaseSemaphore(&pb->pb_EventListSem );
}
/*E*/
/*
** writing packets
*/
/*F*/ static REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2)
{
BOOL having_line;
AW_RESULT rc;
/*
** Arbitration
** ===========================================================
**
** Pseudo code of the arbitration:
**
** if LINE is high (other side is ready to receive) then
** set REQUEST high (tell the other side we're ready to send)
** if LINE is high (other side is still ready to receive) then
** we have the line, do transfer
** reset REQUEST to low (tell other side we're ready to receive)
**
** AW_OK if we could transmit all the data correctly
** AW_BUFF_ERROR if the BufferManagement callback failed
** AW_ERROR if we got the line, but the actual transfer
** failed, perhaps due to a timeout
** AW_ABORT if we couldn't get the line
*/
having_line = FALSE;
if (!TESTLINE(pb)) /* is the line free ? */
{
SETREQUEST(pb); /* indicate our request to send */
if (pb->pb_ArbitrationDelay > 0)
{
pb->pb_TimeReq.tr_time.tv_secs = 0;
pb->pb_TimeReq.tr_time.tv_micro = pb->pb_ArbitrationDelay;
pb->pb_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
DoIO((struct IORequest*)&pb->pb_TimeReq);
}
if (!TESTLINE(pb)) /* is the line still free ? */
having_line = TRUE;
else
{
if (!(pb->pb_Flags & PLIPF_RECEIVING))
CLEARREQUEST(pb); /* reset line state */
d2(("couldn't get the line-1\n"));
}
}
else d2(("couldn't get the line-2\n"));
if (having_line)
{
struct BufferManagement *bm;
if (!(pb->pb_Flags & PLIPF_RECEIVING))
{
d(("having line for: typ %08lx, size %ld\n",ios2->ios2_PacketType,
ios2->ios2_DataLength));
pb->pb_SendFrame.pf_Type = ios2->ios2_PacketType;
pb->pb_SendFrame.pf_Size = ios2->ios2_DataLength + PKTFRAMESIZE_2;
bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
if (!(*bm->bm_CopyFromBuffer)((UBYTE*)pb->pb_SendFrame.pf_Data,
ios2->ios2_Data, ios2->ios2_DataLength))
{
rc = AW_BUFFER_ERROR;
CLEARREQUEST(pb); /* reset line state */
}
else
rc = hwsend(pb) ? AW_OK : AW_ERROR;
}
else
{
d4(("arbitration error!\n"));
rc = AW_ABORTED;
}
}
else
rc = AW_ABORTED;
return rc;
}
/*E*/
/*F*/ static REGARGS VOID dowritereqs(BASEPTR)
{
struct IOSana2Req *currentwrite, *nextwrite;
AW_RESULT code;
ObtainSemaphore(&pb->pb_WriteListSem);
for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head;
nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
currentwrite = nextwrite )
{
if (pb->pb_Flags & PLIPF_RECEIVING)
{
d(("incoming data!"));
break;
}
code = arbitratedwrite(pb, currentwrite);
if (code == AW_ABORTED) /* arbitration failed */
{
pb->pb_Flags |= PLIPF_COLLISION;
d(("couldn't get the line, trying again later\n"));
if ((currentwrite->ios2_Req.io_Error++) > pb->pb_Retries)
{
currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
currentwrite->ios2_WireError = S2WERR_TOO_MANY_RETIRES;
Remove((struct Node*)currentwrite);
DevTermIO(pb, currentwrite);
}
break;
}
else if (code == AW_BUFFER_ERROR) /* BufferManagement callback error */
{
d(("buffer error\n"));
DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE;
currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
Remove((struct Node*)currentwrite);
DevTermIO(pb, currentwrite);
}
else if (code == AW_ERROR)
{
/*
** this is a real line error, upper levels (e.g. Internet TCP) have
** to care for reliability!
*/
d(("error transmitting packet\n"));
DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
Remove((struct Node*)currentwrite);
DevTermIO(pb, currentwrite);
}
else /*if (code == AW_OK)*/ /* well done! */
{
d(("packet transmitted successfully\n"));
pb->pb_DevStats.PacketsSent++;
dotracktype(pb, pb->pb_SendFrame.pf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0);
currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR;
currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
Remove((struct Node*)currentwrite);
DevTermIO(pb, currentwrite);
}
}
ReleaseSemaphore(&pb->pb_WriteListSem);
}
/*E*/
/*
** reading packets
*/
/*F*/ static REGARGS VOID doreadreqs(BASEPTR)
{
LONG datasize;
struct IOSana2Req *got;
ULONG pkttyp;
struct BufferManagement *bm;
if (hwrecv(pb))
{
pb->pb_DevStats.PacketsReceived++;
datasize = pb->pb_ReceiveFrame.pf_Size - PKTFRAMESIZE_2;
dotracktype(pb, pkttyp = pb->pb_ReceiveFrame.pf_Type, 0, 1, 0, datasize, 0);
d(("packet %08lx, size %ld received\n",pkttyp,datasize));
ObtainSemaphore(&pb->pb_ReadListSem);
for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head;
got->ios2_Req.io_Message.mn_Node.ln_Succ;
got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ )
{
if (got->ios2_PacketType == pkttyp )
{
Remove((struct Node*)got);
bm = (struct BufferManagement *)got->ios2_BufferManagement;
if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)pb->pb_ReceiveFrame.pf_Data, datasize))
{
d(("CopyToBuffer: error\n"));
got->ios2_Req.io_Error = S2ERR_SOFTWARE;
got->ios2_WireError = S2WERR_BUFF_ERROR;
DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
}
else
{
got->ios2_Req.io_Error = got->ios2_WireError = 0;
}
got->ios2_Req.io_Flags = 0;
got->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? 0 : (1<<7);
got->ios2_DstAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0 ;
got->ios2_DataLength = datasize;
d(("packet received, satisfying S2Request\n"));
DevTermIO(pb, got);
got = NULL;
break;
}
}
ReleaseSemaphore(&pb->pb_ReadListSem);
}
else
{
DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX);
got = NULL;
pb->pb_DevStats.BadData++;
}
if (got)
{
d(("unknown packet\n"));
pb->pb_DevStats.UnknownTypesReceived++;
ObtainSemaphore(&pb->pb_ReadOrphanListSem);
got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList);
ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
if (got)
{
bm = (struct BufferManagement *)got->ios2_BufferManagement;
if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)pb->pb_ReceiveFrame.pf_Data, datasize))
{
got->ios2_Req.io_Error = S2ERR_SOFTWARE;
got->ios2_WireError = S2WERR_BUFF_ERROR;
}
else
{
got->ios2_Req.io_Error = got->ios2_WireError = 0;
}
got->ios2_Req.io_Flags = 0;
got->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? 0 : (1<<7);
got->ios2_DstAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0 ;
got->ios2_DataLength = datasize;
d(("orphan read\n"));
DevTermIO(pb, got);
}
else
{
dotracktype(pb, pkttyp, 0, 0, 0, 0, 1);
d(("packet thrown away...\n"));
}
}
}
/*E*/
/*
** 2nd level device command dispatcher (~SANA2IOF_QUICK)
*/
/*F*/ static REGARGS VOID dos2reqs(BASEPTR)
{
struct IOSana2Req *ios2;
/*
** Every pending IO message will be GetMsg()'ed and processed. At the
** end of the loop it will be DevTermIO()'ed back to the sender,
** _but_only_if_ it is non-NULL. In such cases the message has been
** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs
** and similar stuff).
** You find the same mimique in the 1st level dispatcher (device.c)
*/
while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort))
{
if (pb->pb_Flags & PLIPF_RECEIVING)
{
d(("incoming data!"));
break;
}
d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command));
switch (ios2->ios2_Req.io_Command)
{
case S2_ONLINE:
if (!goonline(pb))
{
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
}
break;
case S2_OFFLINE:
gooffline(pb);
rejectpackets(pb); /* reject all pending requests */
break;
case S2_CONFIGINTERFACE:
if (pb->pb_Flags & PLIPF_NOTCONFIGURED)
{
ios2->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0;
if (!goonline(pb))
{
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
}
}
else
{
ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
}
break;
}
if (ios2) DevTermIO(pb,ios2);
}
}
/*E*/
/*
** startup,initialisation and termination functions
*/
/*F*/ static struct PLIPBase *startup(void)
{
struct ServerStartup *ss;
struct Process *we;
struct PLIPBase *base;
LOCALSYSBASE;
we = (struct Process*)FindTask(NULL);
d(("waiting for startup msg...\n"));
WaitPort(&we->pr_MsgPort);
ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort);
base = ss->ss_PLIPBase;
d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase));
ReplyMsg((struct Message*)ss);
return base;
}
/*E*/
/*F*/ static VOID readargs(BASEPTR)
{
struct RDArgs *rda;
struct PLIPConfig args = { 0 };
BPTR plipvar, oldinput;
d(("entered\n"));
if (plipvar = Open(CONFIGFILE, MODE_OLDFILE))
{
oldinput = SelectInput(plipvar);
rda = ReadArgs(TEMPLATE , (LONG *)&args, NULL);
if(rda)
{
if (args.timeout)
pb->pb_Timeout = *args.timeout;
if (args.priority)
SetTaskPri((struct Task*)pb->pb_Server, *args.priority);
if (args.mtu && (*args.mtu <= PLIP_MAXMTU))
pb->pb_MTU = *args.mtu;
if (args.bps)
pb->pb_ReportBPS = *args.bps;
if (args.retries && (*args.retries <= PLIP_MAXRETRIES))
pb->pb_Retries = *args.retries;
if (args.sendcrc)
pb->pb_Flags |= PLIPF_SENDCRC;
else
pb->pb_Flags &= ~PLIPF_SENDCRC;
if (args.collisiondelay)
pb->pb_CollisionDelay = *args.collisiondelay;
else
pb->pb_CollisionDelay = PLIP_DEFDELAY +
(pb->pb_Flags & PLIPF_SIDEA) ? PLIP_DELAYDIFF : 0;
if (args.arbitrationdelay)
pb->pb_ArbitrationDelay = *args.arbitrationdelay;
else
pb->pb_ArbitrationDelay = PLIP_DEFARBITRATIONDELAY;
FreeArgs(rda);
}
Close(SelectInput(oldinput));
}
d(("timeout %ld, pri %ld, mtu %ld, bps %ld, retries %ld, flags %08lx, delay %ld\n",
pb->pb_Timeout, (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_MTU, pb->pb_ReportBPS, pb->pb_Retries,
pb->pb_Flags, pb->pb_CollisionDelay));
d(("left\n"));
}
/*E*/
/*F*/ static BOOL init(BASEPTR)
{
BOOL rc = FALSE;
if ((pb->pb_IntSig = AllocSignal(-1)) != -1)
{
pb->pb_IntSigMask = 1L << pb->pb_IntSig;
if (pb->pb_ServerPort = CreateMsgPort())
{
if (pb->pb_TimerPort = CreateMsgPort())
{
memset((VOID*)&pb->pb_TimeReq, 0, sizeof(pb->pb_TimeReq));
pb->pb_TimeReq.tr_node.io_Message.mn_ReplyPort = pb->pb_TimerPort;
if (!OpenDevice( "timer.device", UNIT_MICROHZ, (struct IORequest*)&pb->pb_TimeReq, 0 ))
{
TimerBase = (struct Library *)pb->pb_TimeReq.tr_node.io_Device;
readargs(pb);
rc = TRUE;
}
else
{
d(("couldn't open timer.device"));
}
}
else
{
d(("no timer port\n"));
}
}
else
{
d(("no server port\n"));
}
}
else
{
d(("no signal\n",rc));
}
d(("left %ld\n",rc));
return rc;
}
/*E*/
/*F*/ static VOID cleanup(BASEPTR)
{
struct BufferManagement *bm;
gooffline(pb);
while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement))
FreeVec(bm);
if (TimerBase) CloseDevice((struct IORequest*)&pb->pb_TimeReq);
if (pb->pb_TimerPort) DeleteMsgPort(pb->pb_TimerPort);
if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort);
if (pb->pb_IntSig != -1) FreeSignal(pb->pb_IntSig);
}
/*E*/
/*
** entry point, mainloop
*/
/*F*/ extern VOID SAVEDS ServerTask(void)
{
BASEPTR;
d(("server running\n"));
if (pb = startup())
{
if (init(pb))
{
ULONG recv, portsigmask, timersigmask, wmask;
BOOL running, timerqueued = FALSE;
portsigmask = 1 << pb->pb_ServerPort->mp_SigBit;
timersigmask = 1 << pb->pb_TimerPort->mp_SigBit;
wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | pb->pb_IntSigMask | portsigmask | timersigmask;
for(running=TRUE;running;)
{
if (!(pb->pb_Flags & PLIPF_RECEIVING))
recv = Wait(wmask);
else
SetSignal(0, pb->pb_IntSigMask);
/*if (recv & pb->pb_IntSigMask)*/
if (pb->pb_Flags & PLIPF_RECEIVING)
{
d(("received an interrupt\n"));
doreadreqs(pb);
}
if (recv & portsigmask)
{
d(("SANA-II request(s)\n"));
dos2reqs(pb);
}
if (recv & timersigmask)
{
/* pop message */
AbortIO((struct IORequest*)&pb->pb_TimeReq);
WaitIO((struct IORequest*)&pb->pb_TimeReq);
timerqueued = FALSE;
d(("timer wakeup\n"));
}
/* try now to do write requests (if any pending) */
if (!timerqueued)
{
dowritereqs(pb);
/* don't let the other side wait too long! */
if (pb->pb_Flags & PLIPF_RECEIVING)
{
d(("received an interrupt\n"));
SetSignal(0, pb->pb_IntSigMask);
doreadreqs(pb);
}
/*
** Possible a collision has occurred, which is indicated by a
** special flag in PLIPBase.
**
** Using timer.device we periodically will be waked up. This
** allows us to delay write packets in cases when we cannot get
** the line immediately.
**
** If client and server are very close together, regarding the point
** of performance, the same delay time could even force multiple
** collisions (at least theoretical, I made no practical tests).
** Probably a CSMA/CD-like random-timed delay would be ideal.
*/
if (pb->pb_Flags & PLIPF_COLLISION)
{
extern void KPrintF(char *,...);
pb->pb_Flags &= ~PLIPF_COLLISION;
pb->pb_TimeReq.tr_time.tv_secs = 0;
pb->pb_TimeReq.tr_time.tv_micro = pb->pb_CollisionDelay;
pb->pb_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
/*KPrintF("waiting %ld/%ld\n", pb->pb_TimeReq.tr_time.tv_secs, pb->pb_TimeReq.tr_time.tv_micro);*/
SendIO((struct IORequest*)&pb->pb_TimeReq);
timerqueued = TRUE;
}
}
if (recv & SIGBREAKF_CTRL_C)
{
d(("received break signal\n"));
running = FALSE;
}
}
if (timerqueued)
{
/* finnish pending timer requests */
AbortIO((struct IORequest*)&pb->pb_TimeReq);
WaitIO((struct IORequest*)&pb->pb_TimeReq);
}
}
else
d(("init() failed\n"));
d(("cleaning up\n"));
cleanup(pb);
/* Exec will enable it's scheduler after we're dead. */
Forbid();
/* signal mother we're done */
if (pb->pb_ServerStoppedSigMask)
Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask);
pb->pb_Flags |= PLIPF_SERVERSTOPPED;
}
else
d(("no startup packet\n"));
}
/*E*/